package com.example.skytakeoutserver.handler

import com.example.serverbase.constant.JwtClaimConst.TOKEN
import com.example.serverbase.constant.JwtClaimConst.USER_ID
import com.example.skytakeoutserver.config.cpn.property.JwtProperty
import com.example.skytakeoutserver.data.response.ApiResponse
import com.example.skytakeoutserver.util.AliOSSUtil
import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.databind.ObjectMapper
import io.jsonwebtoken.Claims
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
import lombok.AllArgsConstructor
import lombok.RequiredArgsConstructor
import lombok.SneakyThrows
import lombok.extern.slf4j.Slf4j
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.server.reactive.ServerHttpResponse
import org.springframework.stereotype.Component
import org.springframework.stereotype.Service
import org.springframework.web.server.ServerWebExchange
import org.springframework.web.server.WebFilter
import org.springframework.web.server.WebFilterChain
import reactor.core.publisher.Mono
import java.io.UnsupportedEncodingException
import java.time.Duration
import java.time.Instant
import java.util.Date


@Component
@Slf4j
@AllArgsConstructor
class JwtWebFilter(private val jwtSigner: JwtSigner, private val aliOSSUtil: AliOSSUtil) : WebFilter {

    @Throws(JsonProcessingException::class, UnsupportedEncodingException::class)
    protected fun writeErrorMessage(response: ServerHttpResponse, status: HttpStatus, msg: String?): Mono<Void> {
        response.headers.contentType = MediaType.APPLICATION_JSON
        //val mapper = ObjectMapper()
        // 使用 Result.error() 来创建错误响应
        val errorResponse = ApiResponse<String>(status.value(), msg ?: "Internal Server Error", null)
        //val body = mapper.writeValueAsString(errorResponse)
        val dataBuffer = response.bufferFactory().wrap(ObjectMapper().writeValueAsBytes(errorResponse))
        return response.writeWith(Mono.just(dataBuffer))
    }


    @SneakyThrows
    override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
        val request = exchange.request
        val response = exchange.response
        val path = request.path.value()
        if (
            path.contains("/user/login") ||
            path.contains("//notify") ||
            path.contains("/ws") ||
            path.contains("/admin/employee/login") ||
            path.contains("user/shop/status") ||
            path.startsWith("/v3/swagger-ui/") || // 为Swagger UI的路径
            path.startsWith("/v3/api-docs") || // 为API文档的路径
            path.startsWith("/v3/swagger-resources") || // 为Swagger的资源文件路径
            path.startsWith("/v3/webjars/") || // 为Swagger UI的webjars资源路径
            path == "/v3/swagger-ui.html" || // 如果你的Swagger页面是这个路径
            path == "/v3/doc.html"
        ) return chain.filter(exchange)

        /**
         * TODO: 条件调试
         */
        if (aliOSSUtil.isDebug()) {

        } else {


//        val token = request.headers.getFirst(TOKEN)
//            ?: return writeErrorMessage(response, HttpStatus.NOT_ACCEPTABLE, "没有携带token")
//
//
//        try {
//            val claim = jwtSigner.parseToken(token)
//            //println("用户userId ${claim[jwtSigner.authoritiesTag]}")
//            exchange.attributes[USER_ID] = claim[jwtSigner.authoritiesTag]
//        } catch (e: Exception) {
//            return writeErrorMessage(response, HttpStatus.INTERNAL_SERVER_ERROR, e.message)
//        }
        }
        return chain.filter(exchange)

    }

}

/**
 * @author: ffzs
 * @Date: 2020/8/16 下午8:06
 */
@Service
@RequiredArgsConstructor
@Slf4j
class JwtSigner(val jwtProperties: JwtProperty) {
    val authoritiesTag = "authorities"
    val issuerTag = "identity"

    //val TOKEN_PREFIX = "Bearer "


    fun generateToken(id: Long): String {

        return Jwts.builder()
            .setSubject(id.toString())
            .claim(authoritiesTag, id)
            .signWith(SignatureAlgorithm.HS256, jwtProperties.secretKey)
            .setIssuer(issuerTag)
            .setExpiration(Date.from(Instant.now().plus(Duration.ofMinutes(jwtProperties.ttl))))
            .setIssuedAt(Date(System.currentTimeMillis()))
            .compact()
    }

    fun parseToken(token: String?): Claims {
        return Jwts
            .parser()
            .setSigningKey(jwtProperties.secretKey)
            .parseClaimsJws(token)
            .body
    }
}

